package com.apobates.forum.grief.lang;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.*;

/**
 * java.time包工具类
 *
 * @author xiaofanku
 * @since 20200511
 */
public final class DateTimeUtils {
    public final static String Y = "Year";
    public final static String M = "Month";
    public final static String D = "Day";
    private final static String YMDHMS_L = "yyyy-MM-dd HH:mm:ss";
    private final static String YMDHMS = "yyyyMMddHHmmssSSS";

    private DateTimeUtils() throws Exception {
        throw new Exception("不需要实例工具类");
    }

    /**
     * 格式化当前日期为yyyy-MM-dd HH:mm:ss<14>
     * https://tools.ietf.org/html/rfc3339 示例: 1985-04-12T23:20:50.52Z
     * 1996-12-19T16:39:57-08:00
     *
     * @param date 要求不为null,反之返回空字符串
     * @return
     */
    public static String getRFC3339(LocalDateTime date) {
        if (null == date) {
            return "";
        }
        return date.format(DateTimeFormatter.ofPattern(YMDHMS_L).withZone(ZoneId.systemDefault()));
    }

    /**
     * 使用指定的时区进行格式化
     *
     * @param date 要求不为null,反之返回空字符串
     * @param zone 时区
     * @return
     */
    public static String getRFC3339(LocalDateTime date, ZoneId zone) {
        if (null == date) {
            return "";
        }
        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(zone));
    }

    /**
     * 格式化当前日期为yyyy-MM-ddTHH:mm:ss<15>
     * https://www.iso.org/iso-8601-date-and-time-format.html 示例:
     * 2015-12-14T12:00:29.3387979-05:00 2008-09-15T15:53:00+05:00
     *
     * @param date 要求不为null,反之返回空字符串
     * @return
     */
    public final static String getISO8601(LocalDateTime date) {
        if (null == date) {
            return "";
        }
        return date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    }

    /**
     * 格式化当前日期为yyyyMMdd<16>
     *
     * @return
     */
    public static String getYMD() {
        return getYMDByLine().replaceAll("-", "");
    }

    /**
     * 格式化日期
     *
     * @param date
     * @return
     */
    public static String formatClock(LocalDateTime date) {
        if (null == date) {
            return "-";
        }
        LocalDateTime n = LocalDateTime.now();
        if (!isSameYear(date, n)) { //不是同一年
            return date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
        }
        if (!isSameMonth(date, n)) { //是同一年 // 不是同一个月{return m-d}
            return date.format(DateTimeFormatter.ofPattern("MM月dd日"));
        }
        if (!isSameDay(date, n)) { //同一个月 // 不是同一天
            long dd = diffDays(n, date);
            return (dd <= 1) ? "昨天" : dd + "天前";
        }
        //同一天
        long diffMin = diffMinutes(n, date);
        if (diffMin <= 1) { //一分钟以内
            return "刚刚";
        }
        if (diffMin > 1 && diffMin < 60) { //一小时以内
            return diffMin + "分钟前";
        }
        return Math.round(diffMin / 60) + "小时前";
    }

    /**
     * 格式化指定日期为yyyyMMdd
     *
     * @param date 要求不为null,反之返回空字符串
     * @return
     */
    public static String getYMD(LocalDateTime date) {
        if (null == date) {
            return "";
        }
        return getYMDByLine(date.toLocalDate()).replaceAll("-", "");
    }

    /**
     * 格式化当前日期为yyyy-MM-dd<17>
     *
     * @return
     */
    public static String getYMDByLine() {
        return getYMDByLine(LocalDate.now());
    }

    /**
     * 格式化指定日期为yyyy-MM-dd
     *
     * @param date 要求不为null,反之返回空字符串
     * @return
     */
    public static String getYMDByLine(LocalDate date) {
        if (null == date) {
            return "";
        }
        return date.toString();
    }

    /**
     * 计算昨天的日期
     *
     * @return
     */
    public static LocalDateTime getYesterDay() {
        return LocalDateTime.now().minusDays(1);
    }

    /**
     * 格式化当前日期为HH:mm:ss<18>
     *
     * @return
     */
    public static String getTimeString() {
        return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
    }

    /**
     * 格式化当前日期为yyyyMMddHHmmssSSS<19>
     *
     * @return
     */
    public static String getDateFullFormatString() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(YMDHMS));
    }

    /**
     * 使用指定格式来格式化指定日期
     * @param data 指定日期
     * @param formatString 指定格式
     * @return
     */
    public static String getFormatString(LocalDateTime data, String formatString) {
        if(null == data || !StringUtils.isNotBlank(formatString)){
            return "-";
        }
        return data.format(DateTimeFormatter.ofPattern(formatString));
    }
    /**
     * 指定的日期是否与当前日期是同一天<11>
     *
     * @param date 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameDay(LocalDateTime date) {
        if (null == date) {
            return false;
        }
        return isSameDay(date, LocalDateTime.now());
    }

    /**
     * 两个指定的日期是否是同一天
     *
     * @param date1 要求不为null,反之返回false
     * @param date2 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameDay(LocalDateTime date1, LocalDateTime date2) {
        if (null == date1 || null == date2) {
            return false;
        }
        //
        LocalDate ld1 = date1.toLocalDate();
        LocalDate ld2 = date2.toLocalDate();
        return ld1.getYear() == ld2.getYear() && ld1.getMonthValue() == ld2.getMonthValue() && ld1.getDayOfMonth() == ld2.getDayOfMonth();
    }
    /**
     * 两个指定的日期是否是同一天
     *
     * @param date1 要求不为null,反之返回false
     * @param date2 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameDay(LocalDate date1, LocalDate date2) {
        if (null == date1 || null == date2) {
            return false;
        }
        //
        LocalDate ld1 = date1;
        LocalDate ld2 = date2;
        return ld1.getYear() == ld2.getYear() && ld1.getMonthValue() == ld2.getMonthValue() && ld1.getDayOfMonth() == ld2.getDayOfMonth();
    }
    /**
     * 指定的日期是否与当前日期是同一月<12>
     *
     * @param date 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameMonth(LocalDateTime date) {
        if (null == date) {
            return false;
        }
        return isSameMonth(date, LocalDateTime.now());
    }

    /**
     * 两个指定的日期是否是同一月
     *
     * @param date1 要求不为null,反之返回false
     * @param date2 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameMonth(LocalDateTime date1, LocalDateTime date2) {
        if (null == date1 || null == date2) {
            return false;
        }
        LocalDate ld1 = date1.toLocalDate();
        LocalDate ld2 = date2.toLocalDate();
        return ld1.getYear() == ld2.getYear() && ld1.getMonthValue() == ld2.getMonthValue();
    }

    /**
     * 指定的日期是否与当前日期是同一年<13>
     *
     * @param date 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameYear(LocalDateTime date) {
        if (null == date) {
            return false;
        }
        return isSameYear(date, LocalDateTime.now());
    }

    /**
     * 两个指定的日期是否是同一年<br/>
     *
     * @param date1 要求不为null,反之返回false
     * @param date2 要求不为null,反之返回false
     * @return
     */
    public static boolean isSameYear(LocalDateTime date1, LocalDateTime date2) {
        if (null == date1 || null == date2) {
            return false;
        }
        return date1.toLocalDate().getYear() == date2.toLocalDate().getYear();
    }

    /**
     * 使用默认的时区格式化日期
     *
     * @param date         要求不为null,反之返回空字符串
     * @param formatString 日期格式字符串
     * @return
     */
    public static String formatDateString(LocalDateTime date, String formatString) {
        if (null == date) {
            return "";
        }
        try {
            return date.format(DateTimeFormatter.ofPattern(formatString));
        } catch (Exception e) {
        }
        return "-";
    }

    /**
     * 获取上月的第一天凌晨日期(00:00:00)<20>
     *
     * @return
     */
    public static LocalDateTime getPreviousMonthFirstDayEarlyMorning() {
        return LocalDate.now().minusMonths(1).atStartOfDay();
    }

    /**
     * 获取上月的第后一天午夜日期(23:59:59)<21>
     *
     * @return
     */
    public static LocalDateTime getPreviousMonthLastDayMidnight() {
        LocalDateTime prevMonthFirstDay = getPreviousMonthFirstDayEarlyMorning();
        return prevMonthFirstDay.withHour(23).withMinute(59).withSecond(29);
    }

    /**
     * 获取本月的第一天凌晨日期(00:00:00)<2>
     *
     * @return
     */
    public static LocalDateTime getCurrentMonthFirstDayEarlyMorning() {
        return LocalDate.now().withDayOfMonth(1).atStartOfDay();
    }

    /**
     * 获取今天的凌晨(00:00:00)<1> 适用的范围广
     *
     * @return
     */
    public static LocalDateTime getTodayEarlyMorning() {
        return LocalDate.now().atStartOfDay();
    }

    /**
     * 获取今天的午夜日期(23:59:59)
     *
     * @return
     */
    public static LocalDateTime getTodayMidnight() {
        LocalDate date = LocalDate.now();
        return LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 23, 59, 59);
    }

    /**
     * 将指定日期设置为凌晨(00:00:00)<3> 用在几个作业(cron)类上
     *
     * @param date 要求不为null,否则抛出NPE
     * @return
     */
    public static LocalDateTime setDateEarlyMorning(LocalDateTime date) {
        Objects.requireNonNull(date);
        return LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 0, 0, 0);
    }

    /**
     * 将指定日期设置为午夜(23:59:59)<4>
     *
     * @param date 要求不为null,否则抛出NPE
     * @return
     */
    public static LocalDateTime setDateMidnight(LocalDateTime date) {
        Objects.requireNonNull(date);
        return LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 23, 59, 59);
    }

    /**
     * 昨天午夜的日期(23:59:59)<5>
     *
     * @return
     */
    public static LocalDateTime getYesterdayMidnight() {
        LocalDateTime yesDay = getYesterDay();
        return LocalDateTime.of(yesDay.getYear(), yesDay.getMonthValue(), yesDay.getDayOfMonth(), 23, 59, 59);
    }

    /**
     * 获得指定月份第一天凌晨(00:00:00)<6>
     *
     * @param year  年
     * @param month 月
     * @return
     */
    public static LocalDateTime getFirstDayEarlyMorningOfMonth(int year, int month) {
        LocalDate ld = LocalDate.of(year, month, 1);
        return ld.atStartOfDay();
    }

    /**
     * 获得指定月份最后一天午夜(23:59:59)<7>
     *
     * @param year  年
     * @param month 月
     * @return
     */
    public static LocalDateTime getLastDayMidnightOfMonth(int year, int month) {
        LocalDate monthOneDay = getFirstDayEarlyMorningOfMonth(year, month).toLocalDate();
        int lastDay = monthOneDay.lengthOfMonth();
        return LocalDateTime.of(year, month, lastDay, 23, 59, 59);
    }

    /**
     * 两个日期之间天数差<8>
     *
     * @param date1 要求不为null,反之返回-1
     * @param date2 要求不为null,反之返回-1
     * @return 最近的为date1, 返回正值;反之返回负值
     */
    public static long diffDays(LocalDateTime date1, LocalDateTime date2) {
        if (null == date1 || null == date2) {
            return -1;
        }
        return date2.until(date1, ChronoUnit.DAYS);
    }

    /**
     * 两个日期之间分钟数差<9>
     *
     * @param date1 要求不为null,反之返回-1
     * @param date2 要求不为null,反之返回-1
     * @return 最近的为date1, 返回正值;反之返回负值
     */
    public static long diffMinutes(LocalDateTime date1, LocalDateTime date2) {
        if (null == date1 || null == date2) {
            return -1;
        }
        return date2.until(date1, ChronoUnit.MINUTES);
    }

    /**
     * 指定的日期在{limit}{calendarUnit}后,是否小于当前日期 例: c1在5小时后，是否小于当前日期<10>
     *
     * @param c1    要求不为null,反之返回false
     * @param unit  TemporalUnit单位,例:年:ChronoUnit.YEARS,月:ChronoUnit.MONTHS,日:ChronoUnit.DAYS,小时:ChronoUnit.HOURS,分钟:ChronoUnit.MINUTES,秒:ChronoUnit.SECONDS
     * @param limit 单位值
     * @return 如果当前日期大于c1累加后的值返回true
     */
    public static boolean isFeatureDate(LocalDateTime c1, TemporalUnit unit, int limit) {
        if (null == c1) {
            return false;
        }
        LocalDateTime ldt = c1.plus(limit, unit);
        return LocalDateTime.now().isBefore(ldt);
    }

    /**
     * 判断指定的日期是否是未来时
     *
     * @param dateTime 要求不为null,反之返回false
     * @return 如果当前日期大于参数日期返回false, 若小于返回true
     */
    public static boolean isFeatureDate(LocalDateTime dateTime) {
        if (null == dateTime) {
            return false;
        }
        return LocalDateTime.now().isBefore(dateTime);
    }

    /**
     * 使用yyyy-MM-dd HH:mm:ss格式解析日期
     *
     * @param timeString 日期字符串.要求不为null,否则抛出NPE
     * @return
     */
    public static LocalDateTime parseDate(String timeString) {
        Objects.requireNonNull(timeString);
        return parseDate(timeString, YMDHMS_L);
    }

    /**
     * 使用指定的格式解析日期<br/>
     *
     * @param timeString   日期字符串.要求不为null,否则抛出NPE
     * @param formatString 日期格式字符串
     * @return
     */
    public static LocalDateTime parseDate(String timeString, String formatString) {
        Objects.requireNonNull(timeString);
        return LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(formatString));
    }

    /**
     * 当前日期在指定分钟后的日期<br/>
     *
     * @param minutelimit 分钟数
     * @return
     */
    public static LocalDateTime addMinuteForDate(int minutelimit) {
        return LocalDateTime.now().plusMinutes(minutelimit);
    }

    /**
     * 将指定的日期加上指定的分钟<br/>
     *
     * @param date        要求不为null,否则抛出NPE
     * @param minutelimit 分钟数
     * @return
     */
    public static LocalDateTime addMinuteForDate(LocalDateTime date, int minutelimit) {
        Objects.requireNonNull(date);
        return date.plusMinutes(minutelimit);
    }

    /**
     * 当前日期在指定小时后的日期<br/>
     *
     * @param hourlimit 小时数
     * @return
     */
    public static LocalDateTime addHourForDate(int hourlimit) {
        return LocalDateTime.now().plusHours(hourlimit);
    }

    /**
     * 将指定的日期加上指定的小时<br/>
     *
     * @param date      要求不为null,否则抛出NPE
     * @param hourlimit 小时数
     * @return
     */
    public static LocalDateTime addHourForDate(LocalDateTime date, int hourlimit) {
        Objects.requireNonNull(date);
        return date.plusHours(hourlimit);
    }

    /**
     * 当前日期在指定天后的日期<br/>
     *
     * @param daylimit 天数
     * @return
     */
    public static LocalDateTime addDayForDate(int daylimit) {
        return LocalDateTime.now().plusDays(daylimit);
    }

    /**
     * 将指定的日期加上指定的天<br/>
     *
     * @param date     要求不为null,否则抛出NPE
     * @param daylimit 天数
     * @return
     */
    public static LocalDateTime addDayForDate(LocalDateTime date, int daylimit) {
        Objects.requireNonNull(date);
        return date.plusDays(daylimit);
    }

    /**
     * 当前日期在指定月后的日期<br/>
     *
     * @param monthlimit 月数
     * @return
     */
    public static LocalDateTime addMonthForDate(int monthlimit) {
        return LocalDateTime.now().plusMonths(monthlimit);
    }

    /**
     * 将指定的日期加上指定的月<br/>
     *
     * @param date       要求不为null,否则抛出NPE
     * @param monthlimit 月数
     * @return
     */
    public static LocalDateTime addMonthForDate(LocalDateTime date, int monthlimit) {
        Objects.requireNonNull(date);
        return date.plusMonths(monthlimit);
    }

    /**
     * 当前日期在指定年后的日期<br/>
     *
     * @param yearlimit 年数
     * @return
     */
    public static LocalDateTime addYearForDate(int yearlimit) {
        return LocalDateTime.now().plusYears(yearlimit);
    }

    /**
     * 将指定的日期加上指定的年<br/>
     *
     * @param date      要求不为null,否则抛出NPE
     * @param yearlimit 年数
     * @return
     */
    public static LocalDateTime addYearForDate(LocalDateTime date, int yearlimit) {
        Objects.requireNonNull(date);
        return date.plusYears(yearlimit);
    }

    /**
     * 指定日期的前几天日期<br/>
     *
     * @param date 要求不为null,否则抛出NPE
     * @param day  天数
     * @return
     */
    public static LocalDateTime beforeDayForDate(LocalDateTime date, int day) {
        Objects.requireNonNull(date);
        return date.minusDays(day);
    }

    /**
     * 指定日期的前几分钟日期<br/>
     *
     * @param date   要求不为null,否则抛出NPE
     * @param minute 分钟数
     * @return
     */
    public static LocalDateTime beforeMinuteForDate(LocalDateTime date, int minute) {
        Objects.requireNonNull(date);
        return date.minusMinutes(minute);
    }

    /**
     * 将指定的日期转成unix timestamp
     *
     * @param date 要求不为null,反之返回0
     * @return
     */
    public static Integer covertTimestamp(LocalDateTime date) {
        if (null == date) {
            return 0;
        }
        Long d = Timestamp.valueOf(date).getTime() / 1000L;
        return d.intValue();
    }

    /**
     * 将指定的unix timestamp转成util.LocalDateTime
     *
     * @param timestamp 要求不为null,否则抛出NPE.unix 时间戳,例:1589316 时间戳是自 1970 年 1 月 1 日（00:00:00 GMT）以来的秒数。它也被称为 Unix 时间戳（Unix Timestamp）。
     * @return
     */
    public static LocalDateTime getDateTimeByUnixTimestamp(Integer timestamp) {
        Objects.requireNonNull(timestamp);
        return new Timestamp(timestamp * 1000L).toLocalDateTime();
    }

    /**
     * 获得当前的unix timestamp
     *
     * @return
     */
    public static Integer getUnixTimestamp() {
        Long d = Timestamp.valueOf(LocalDateTime.now()).getTime() / 1000L;
        return d.intValue();
    }

    /**
     * 输出当前日期所在年(yyyy)和月(MM)
     *
     * @return key=CommonUtils.Y(ear)|M(onth), Y对应四位数字的年,M对应两位数的月
     */
    public static Map<String, String> getCurrentY4M2() {
        return getYearAndMonth(LocalDate.now());
    }

    /**
     * 输出指定日期所在年(yyyy)和月(MM)
     *
     * @param date java.time.LocalDate 日期,要求不为null,反之返回空集合
     * @return key=DateTimeUtils.Y(ear)|M(onth), Y对应四位数字的年,M对应两位数的月
     */
    public static Map<String, String> getYearAndMonth(LocalDate date) {
        if (null == date) {
            return Collections.emptyMap();
        }
        String[] ymArray = date.toString().split("-");
        return Map.ofEntries(Map.entry(DateTimeUtils.Y, ymArray[0]), Map.entry(DateTimeUtils.M, ymArray[1]));
    }

    /**
     * 将java.util.Calendar 转为java.time.LocalDateTime
     * 注意:Jdk8和以上的环境都不要使用java.util.Calendar,java.util.Date,java.text.SimpleDateFormat
     *
     * @param calendar 要求不为null,否则抛出NPE
     * @return
     */
    public static LocalDateTime toLocalDateTime(Calendar calendar) {
        Objects.requireNonNull(calendar);
        TimeZone tz = calendar.getTimeZone();
        ZoneId zid = (null == tz) ? ZoneId.systemDefault() : tz.toZoneId();
        return LocalDateTime.ofInstant(calendar.toInstant(), zid);
    }

    /**
     * 将 java.time.LocalDateTime 转为java.util.Date
     * 注意:Jdk8和以上的环境都不要使用java.util.Calendar,java.util.Date,java.text.SimpleDateFormat
     *
     * @param dateTime 要求不为null,否则抛出NPE
     * @return
     */
    public static Date toDate(LocalDateTime dateTime) {
        Objects.requireNonNull(dateTime);
        ZoneId systemZone = ZoneId.systemDefault();
        ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(Instant.now());
        Instant instant = dateTime.toInstant(currentOffsetForMyZone);
        return Date.from(instant);
    }

    /**
     * 以时区ID参照转化为java.util.Date
     *
     * @param dateTime 时间.要求不为null,否则抛出NPE
     * @param zone     时区ID
     * @return
     */
    public static Date toZoneDate(LocalDateTime dateTime, ZoneId zone) {
        Objects.requireNonNull(dateTime);
        Instant instant = dateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 填充数据源中时间的空值,主要用于连续日期的统计
     *
     * @param start   开始日期
     * @param finish  结束日期
     * @param rawdata 数据源,要求Key=YYYY-MM-DD
     * @return
     */
    public static TreeMap<String, Long> fillEmptyResult(LocalDateTime start, LocalDateTime finish, Map<String, Long> rawdata) {
        TreeMap<String, Long> data = new TreeMap<>();
        LocalDateTime loopDate = start;
        do {
            String loopKey = DateTimeUtils.getYMDByLine(loopDate.toLocalDate());
            Long size = rawdata.getOrDefault(loopKey, 0L);
            data.put(loopKey, size);
            loopDate = DateTimeUtils.addDayForDate(loopDate, 1);
        } while (!DateTimeUtils.isSameDay(loopDate, DateTimeUtils.addDayForDate(finish, 1)));
        return data;
    }

    /**
     * 格式化指定日期为yyyy-MM
     *
     * @return
     */
    public static String getYMString(LocalDate date) {
        if (null == date) {
            return "";
        }
        return date.format(DateTimeFormatter.ofPattern("YYYY-MM"));
    }

    /**
     * 指定日期的前几个月的日期<br/>
     *
     * @param date  要求不为null,否则抛出NPE
     * @param month 前几个月？
     * @return
     */
    public static LocalDateTime beforeMonthForDate(LocalDateTime date, int month) {
        Objects.requireNonNull(date);
        return date.minusMonths(month);
    }

    /**
     * 填充数据源中时间的空值,主要用于连续日期的统计
     *
     * @param start   开始日期
     * @param finish  结束日期
     * @param rawdata 数据源,要求Key=YYYY-MM-DD
     * @return
     */
    public static TreeMap<String, BigDecimal> fillYmInEmptyBigDecimalResult(LocalDateTime start,
                                                                            LocalDateTime finish,
                                                                            Map<String, BigDecimal> rawdata) {
        TreeMap<String, BigDecimal> data = new TreeMap<>();
        LocalDateTime loopDate = start;
        do {
            String loopKey = DateTimeUtils.getYMString(loopDate.toLocalDate());
            BigDecimal size = rawdata.getOrDefault(loopKey, BigDecimal.ZERO);
            data.put(loopKey, size);
            loopDate = DateTimeUtils.addMonthForDate(loopDate, 1);
        } while (!DateTimeUtils.isSameMonth(loopDate, DateTimeUtils.addMonthForDate(finish, 1)));
        return data;
    }

    /**
     * 填充数据源中时间的空值,主要用于连续日期的统计
     *
     * @param start   开始日期
     * @param finish  结束日期
     * @param rawdata 数据源,要求Key=YYYY-MM-DD
     * @return
     */
    public static TreeMap<String, Long> fillYmInEmptyLongResult(LocalDateTime start,
                                                                LocalDateTime finish,
                                                                Map<String, Long> rawdata) {
        TreeMap<String, Long> data = new TreeMap<>();
        LocalDateTime loopDate = start;
        do {
            String loopKey = DateTimeUtils.getYMString(loopDate.toLocalDate());
            Long size = rawdata.getOrDefault(loopKey, 0L);
            data.put(loopKey, size);
            loopDate = DateTimeUtils.addMonthForDate(loopDate, 1);
        } while (!DateTimeUtils.isSameMonth(loopDate, DateTimeUtils.addMonthForDate(finish, 1)));
        return data;
    }

    /**
     * 返回本月的最后一天
     * @return
     */
    public static LocalDate getLastDayOfMonth(){
        return  LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 今天是本月的最后一天吗
     * @return 是返回true,false表示不是
     */
    public static boolean todayIsLastDayOfMonth(){
        return isSameDay(getLastDayOfMonth(), LocalDate.now());
    }

    /**
     * 丢掉时间戳中的秒信息
     * @param timestamp 精确到耗秒的
     * @return 返回unix时间戳,若参数不可能返回-1
     */
    public static long discardSecond(long timestamp) {
        if(timestamp<=0){
            return -1L;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTimeInMillis() / 1000;
    }

    /**
     * 丢掉日期中的秒信息
     * @param date 日期
     * @return 返回unix时间戳,若参数不可能返回-1
     */
    public static long discardSecond(Date date) {
        if(null == date){
            return -1L;
        }
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTimeInMillis() / 1000;
    }
}
